# !/usr/bin/python
# -*- coding: utf-8 -*-
'''
@File    :   213_打家劫舍2.py
@Time    :   2021/11/06 14:08:59
@Author  :   Qingxiang Zhang
@Version :   1.0
@Contact :   344285081@qq.com
@Desc    :   动态规划
@Software:    Vscode
'''
'''
难度：中等
你是一个专业的小偷，计划偷窃沿街的房屋，每间房内都藏有一定的现金。这个地方所有的房屋都 围成一圈 ，这意味着第一个房屋和最后一个房屋是紧挨着的。同时，相邻的房屋装有相互连通的防盗系统，如果两间相邻的房屋在同一晚上被小偷闯入，系统会自动报警 。
给定一个代表每个房屋存放金额的非负整数数组，计算你 在不触动警报装置的情况下 ，今晚能够偷窃到的最高金额。
示例 1：
输入：nums = [2,3,2]
输出：3
解释：你不能先偷窃 1 号房屋（金额 = 2），然后偷窃 3 号房屋（金额 = 2）, 因为他们是相邻的。
示例 2：
输入：nums = [1,2,3,1]
输出：4
解释：你可以先偷窃 1 号房屋（金额 = 1），然后偷窃 3 号房屋（金额 = 3）。
     偷窃到的最高金额 = 1 + 3 = 4 。
示例 3：
输入：nums = [0]
输出：0
 提示：
1 <= nums.length <= 100
0 <= nums[i] <= 1000
'''

"""
- **第一步：确定动态规划状态**
  直接定义题目所求的偷窃的最高金额，所以`dp[i]`表示偷窃第`i`号房子能得到的最高金额。
- **第二步：写出状态转移方程**
  和上个题目类似，这个题目不一样的是现在所有房屋都围成一个圈，相比于上个问题又增加了一个限制，这样一来第一个房子和最后一个房子只能选择其中一个偷窃了。所有我们把这个问题拆分成两个问题：
  - 偷窃了第一个房子，此时对应的是`nums[1:]`，得到最大的金额value是`v1`。
  - 偷窃了最后一个房子，此时对应的是`nums[:n-1]`(其中n是所有房子的数量)，得到的最大金额value是`v2`。
    最后的结果就是取这两种情况的最大值，即`max(v1,v2)`。
  每个子问题就和上题是一样的了，所以可以直接得到状态转移方程还是`dp[i]=max(dp[i-2]+nums[i],dp[i-1])`
- **第三步：考虑初始化条件**
  初始化一个房子和两个房子的情况就是`dp[0]=nums[0]，dp[1]=max(nums[0],nums[1])`。
- **第四步：考虑输出状态**
  直接返回状态转移数组的最后一个值就是所求的最大偷窃金额。
- **第五步：考虑对时间，空间复杂度的优化**
时间复杂度为$O(N)$不能再优化了，空间复杂度方面如果用动态规划是不能优化，但是如果用迭代的方法只存储临时变量来记录每一步计算结果，这样可以降到$O(1)$。
"""
class Solution:
    def rob(self, nums) -> int:
        if not nums:
            return 0
        if len(nums) <= 2:
            return max(nums)
        def helper(nums):
            if len(nums) <= 2:
                return max(nums)
            dp = [0] *len(nums)
            dp[0] = nums[0]
            dp[1] = max(nums[0],nums[1])
            for i in range(2,len(nums)):
                dp[i] = max(dp[i-1],dp[i-2]+nums[i])
            return dp[-1]
        return max(helper(nums[1:]),helper(nums[:-1]))
